package com.openNetty.server.nettyserver;

import com.openNetty.common.system.FileUtils;
import com.openNetty.common.system.IOUtil;
import com.openNetty.common.system.LoggerUtil;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.stream.ChunkedWriteHandler;

import java.io.*;
import java.net.URL;



/**
 * netty server
 *
 * @author zhenggm
 */
public class NettyContainer {

    private static LoggerUtil logger;

    public static void main(String[] args) throws IOException {
        init();
        initTimer();
        start();
    }

    /**
     * 启动定时任务管理器
     */
    private static void initTimer() {
        logger.info("任务列表启动中");
        // 取消quartz检查更新
        System.setProperty("org.terracotta.quartz.skipUpdateCheck", "true");
//        QuartzManager.addJob("加密文件任务", EncFileTask.class, Global.properties.getProperty("back.encfiletask"));
//        QuartzManager.addJob("清理加密文件夹任务", CleanNodeFileTask.class, Global.properties.getProperty("back.cleanfile"));
        logger.info("任务列表启动完成");

    }

    public static void init() throws IOException {

        URL root = null;
        try {
            root = new File(IOUtil.getCurrentExecutePath(NettyContainer.class)).getParentFile().getParentFile().toURI().toURL();
            LoggerUtil.build(FileUtils.mergePath(root.getPath(), "config"));
            logger = LoggerUtil.getLogger(NettyContainer.class);
            logger.info("load Log properties success");

            String nodePath = root.getPath() + "config/back.properties";
            // 加载服务器属性配置文件
            //  InputStream inputStream = ServerStart.class.getResourceAsStream(nodePath); //测试路径
            FileInputStream inputStream = new FileInputStream(nodePath);
            Global.properties.load(inputStream);
            Global.PORT = Global.properties.getProperty("back.port");
            Global.ROOT = Global.properties.getProperty("back.root");
            logger.info("load back properties success");

            String keyPath = root.getPath() + "config/key";
            getKey(keyPath);

        } catch (Exception e) {
            System.out.println(System.currentTimeMillis() + " [ERROR] Server start failed. logger can not init.please check log config file.");
            e.printStackTrace();
        }
    }

    /**
     * 加载秘钥文件
     * @param keyPath
     * @throws IOException
     */
    public static void getKey(String keyPath) throws IOException {
        logger.info("开始加载秘钥路径：" + keyPath);
        File key = new File(keyPath);
        if (key.isDirectory()) {
            File[] files = key.listFiles();
            for (File fileIndex : files) {
                //如果这个文件是目录，则进行递归搜索
                if (fileIndex.isDirectory()) {
                    getKey(fileIndex.getPath());
                } else {
                    //如果文件是秘钥进行存储
                    receiveSecret(fileIndex);
                }
            }
        }
    }

    public static void receiveSecret(File keyFile) throws IOException {
        try {
            InputStream inputStream = new FileInputStream(keyFile);//文件内容的字节流
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream); //得到文件的字符流
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader); //放入读取缓冲区
            String readd = "";
            StringBuffer stringBuffer = new StringBuffer();
            while ((readd = bufferedReader.readLine()) != null) {
                stringBuffer.append(readd);
            }
            inputStream.close();
            String keystr = stringBuffer.toString();
            Global.keyMap.put(String.valueOf(keyFile.getName().hashCode()), keystr);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
            throw new IOException("秘钥文件加载失败");
        }
    }

    public static void start() {
        logger.info("NettyContainer Server is starting");
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childHandler(new ChildChannelHandler());

            //绑定端口、同步等待
            ChannelFuture channelFuture = serverBootstrap.bind(Integer.parseInt(Global.PORT)).sync();
            logger.info("NettyContainer Server is started");
            //等待服务监听端口关闭
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //退出，释放线程等相关资源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    private static class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            // 服务端，对请求解码
            ch.pipeline().addLast("http-decoder",
                    new HttpRequestDecoder());
            // 聚合器，把多个消息转换为一个单一的FullHttpRequest或是FullHttpResponse
            ch.pipeline().addLast("http-aggregator",
                    new HttpObjectAggregator(1024 * 1024 * 1024));
            // 服务端，对响应编码
            ch.pipeline().addLast("http-encoder",
                    new HttpResponseEncoder());
            // 块写入处理器
            ch.pipeline().addLast("http-chunked",
                    new ChunkedWriteHandler());
            // 自定义服务端处理器
            ch.pipeline().addLast(new NodeServerHandler());
        }
    }
}
